function times33(s) {
	var result=0;
	
	for(var i=0; i<s.length; i++) {
		result = (result * 33 + s.charCodeAt(i)) & 0x7fffffff;
	}
	
	return result;
}

function getStyleSheetByHref(href) {
	var domain = 'http://' + location.host;
	var dlen = domain.length;
	
	for(var i = 0; i < document.styleSheets.length; i++) {
		var tmp_href = document.styleSheets[i].href;
		if(!tmp_href) {
			continue;
		}
		
		if(0 == tmp_href.indexOf(domain)) {
			tmp_href = tmp_href.substr(dlen);
		}

		if(href == tmp_href || ('/' + href) == tmp_href) {
			return document.styleSheets[i];
		}
	}
	
	return false;
}

function getStyleSheetRules(ss) {
	return ss.rules ? ss.rules : ss.cssRules;
}

function sync(test, callback, millis) {
	var iTimerID = null;
	millis = millis || 500;
	
	var oncallback = function() {
		if(test()) {
			window.clearInterval(iTimerID);
			iTimerID = null;
			callback();
		}
	}
	
	iTimerID = window.setInterval(oncallback, millis);
}

function getHttpRequest() {
	if (window.XMLHttpRequest) {
		return new XMLHttpRequest();
	} else if(window.ActiveXObject){
		return new ActiveXObject("MsXml2.XmlHttp");
	}
	
	return null;
}

function ajaxGet(xh, url, callback) {
	xh.onreadystatechange = function() {
		if(xh.readyState == 4) {
			if(xh.status == 200 || xh.status == 304) {
				callback(xh.responseText);
			} else {
				alert('XML request error: ' + xh.statusText + ' (' + xh.status + ')');
			}
		}
	}
	
	xh.open('GET', url, true);
	xh.send(null);
}

var Loader = {};

Loader.loadcss  = function(url, test, callback) {
	var id = times33(url);
	if(document.getElementById(id)) {
		//alert(url + ' already loaded!');
		callback();
		return true;
	}
	
	var css = document.createElement('link');
	css.id = id;
    css.rel = 'stylesheet';
    css.type = 'text/css';
    css.href = url;
    document.getElementsByTagName('head')[0].appendChild(css);
    
	sync(test, callback);
}

Loader.loadjs = function(url, callback) {
	var id = times33(url);
	if(document.getElementById(id)) {
		//alert(url + ' already loaded!');
		callback();
		return true;
	}

	ajaxGet(getHttpRequest(), url, function(s) {
		var js = document.createElement('script');
		js.id = id;
		js.type = 'text/javascript';
		js.text = s;
		document.getElementsByTagName('head')[0].appendChild(js);
		callback();
	});
}

Loader.load = function(js, css, callback, cssEndPre) {
	var js_loaded = css_loaded = 0;
	js = 'string' == typeof(js) ? [js] : js;
	css = 'string' == typeof(css) ? [css] : css;
	cssEndPre = cssEndPre || '#stylesheet_load_';

	var onload_css = function() {
		css_loaded++;

		if(css_loaded < css.length) {
			Loader.loadcss(
				css[css_loaded],
				
				function() {
					var ss = getStyleSheetByHref(css[css_loaded]);
					if(!ss) {
						return false;
					}
					
					rules = getStyleSheetRules(ss);
					if(rules.length <= 0) {
						return false;
					}
					
					var selectorText = rules[rules.length - 1].selectorText;
					return selectorText == cssEndPre + css_loaded;
				},
				
				onload_css
			);
		} else {
			callback();
		}
	}
	
	var onload_js = function() {
		js_loaded++;
		
		if(js_loaded < js.length) {
			Loader.loadjs(js[js_loaded], onload_js);
		} else {
			Loader.loadcss(
				css[0],
				
				function() {
					var ss = getStyleSheetByHref(css[css_loaded]);
					if(!ss) {
						return false;
					}
					
					rules = getStyleSheetRules(ss);
					if(!rules) {
						return false;
					}
					
					var selectorText = rules[rules.length - 1].selectorText;
					return selectorText == cssEndPre + css_loaded;
				},
				
				onload_css
			);
		}
	}
	
	Loader.loadjs(js[0], onload_js);
}